# # 导入函数库
# from jqdata import *
#
#
# # 初始化函数，设定基准等等
# def initialize(context):
#     # 设定沪深300作为基准
#     set_benchmark('000300.XSHG')
#     # 开启动态复权模式(真实价格)
#     set_option('use_real_price', True)
#     # 赋值，防止代码没有运行到月末或者月初函数钱没有该属性报错
#     g.first_day_monthly = 1992
#     g.last_day_monthly = 1992
#     # 输出内容到日志 log.info()
#     log.info('初始函数开始运行且全局只运行一次')
#     g.stock_num = 200
#     g.stock_buy_num = 10
#     g.sotck_money = 10000
#     g.stop_loss_rate = 0.2
#
#     # 过滤掉order系列API产生的比error级别低的log
#     # log.set_level('order', 'error')
#
#     ### 股票相关设定 ###
#     # 股票类每笔交易时的手续费是：买入时佣金万分之三，卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
#     set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5),
#                    type='stock')
#
#     ## 运行函数（reference_security为运行时间的参考标的；传入的标的只做种类区分，因此传入'000300.XSHG'或'510300.XSHG'是一样的）
#     # 盘前每月第一个交易日  9:27 才能获取到开盘价
#     run_monthly(before_market_open_first_monthly, monthday=1, time='9:27', reference_security='000300.XSHG')
#     # 开盘前运行
#     run_daily(before_market_open, time='9:28', reference_security='000300.XSHG')
#
#     # 开盘时运行
#     run_monthly(market_open_last_monthly, monthday=-1, time='14:56', reference_security='000300.XSHG')
#
#     run_daily(market_open, time='14:57', reference_security='000300.XSHG')
#
#
# def before_market_open_first_monthly(context):
#     g.first_day_monthly = context.current_dt.date();
#
#
# def market_open_last_monthly(context):
#     g.last_day_monthly = context.current_dt.date();
#
#
# ## 开盘前运行函数
# def before_market_open(context):
#     # 输出运行时间
#     log.info('函数运行时间(before_market_open)：' + str(context.current_dt.date()))
#     if (context.current_dt.date() == g.first_day_monthly):
#         # 待买股票
#         to_buy_sotcks = check_sotck(context)
#         stock_buy_num = calc_available_stock_num(context)
#         calc_available_cash(context, stock_buy_num)
#         to_buy_sotcks = to_buy_sotcks[:g.stock_buy_num]
#         order_stock(to_buy_sotcks)
#
#     return
#
#
# def calc_available_stock_num(context):
#     hold_num = len(list(context.portfolio.positions.keys()))
#     stock_buy_num = g.stock_buy_num - hold_num
#     log.info(f"当前持有股票数量：{hold_num}，剩余可买入股票数量：{stock_buy_num}")
#     return stock_buy_num
#
#
# # 计算可用现金
# def calc_available_cash(context, stock_buy_num):
#     cash = context.portfolio.available_cash
#     expected_cach = g.sotck_money * stock_buy_num
#     in_cash = expected_cach - cash
#     if (in_cash > 0):
#         # 补钱
#         inout_cash(in_cash, pindex=0)
#         log.info(f"余额不够，需要充钱，当前余额为：{cash},充值:{expected_cach}")
#
#     log.info(f"当前余额{context.portfolio.available_cash}")
#
#
# ## 开盘时运行函数
# def market_open(context):
#     log.info('函数运行时间(market_open):' + str(context.current_dt.time()))
#     ## 获取持仓列表
#     sell_list = list(context.portfolio.positions.keys())
#     if (context.current_dt.date() == g.last_day_monthly):
#         log.info("月末执行卖出策略")
#         sell_stock(sell_list)
#     else:
#         log.info("每日止损")
#         stop_loss_strategy(context, sell_list)
#
#
# # 止损点 当日最低价低于(1-rate)*买入价 卖出
# def stop_loss_strategy(context, sell_list):
#     sell_list = filter_no_low_limit(sell_list)
#     for stock_code in sell_list:
#         acc_avg_cost = context.portfolio.positions[stock_code].acc_avg_cost
#         tick = get_current_tick(stock_code)
#         day_low = tick.low
#         if day_low < (1 - g.stop_loss_rate) * acc_avg_cost:
#             log.info(
#                 f"跌破买入价超过{(1 - g.stop_loss_rate) * acc_avg_cost}.买入价:{acc_avg_cost},当日最低价:{day_low}")
#             order_target(stock_code, 0)
#         else:
#             log.info(
#                 f"----没有跌破买入价超过{(1 - g.stop_loss_rate) * acc_avg_cost}.买入价:{acc_avg_cost},当日最低价:{day_low}")
#
#
# def order_stock(to_buy_sotcks):
#     # 过滤掉开盘涨停股票
#     to_buy_sotcks = filter_no_high_limit(to_buy_sotcks)
#     # 过滤掉当日停牌的股票
#     to_buy_sotcks = filter_paused(to_buy_sotcks)
#     for stock in to_buy_sotcks:
#         order_value(stock, g.sotck_money)
#         log.info(f"买入股票代码：{stock}")
#
#
# def sell_stock(sell_sotcks):
#     sell_sotcks = filter_no_low_limit(sell_sotcks)
#     for stock in sell_sotcks:
#         order_target(stock, 0)
#         log.info(f"卖出股票代码：{stock}")
#
#
# def filter_st(stocks):
#     current_data = get_current_data()
#     filtered = []
#     for key in stocks:
#         log.info(f"{key}:{current_data[key].is_st}")
#         if current_data[key].is_st == False:
#             filtered.append(key)
#     return filtered
#
#
# def filter_paused(stocks):
#     current_data = get_current_data()
#     filtered = []
#     for key in stocks:
#         log.info(f"{key}:{current_data[key].paused}")
#         if current_data[key].paused == False:
#             filtered.append(key)
#     return filtered
#
#
# def filter_no_high_limit(stocks):
#     current_data = get_current_data()
#     filtered = []
#     for key in stocks:
#         ## 当前开盘价等于涨停
#         if current_data[key].high_limit > current_data[key].day_open:
#             filtered.append(key)
#         else:
#             log.info(f"由于涨停不能买入的股票：{key}")
#     return filtered
#
#
# def filter_no_low_limit(stocks):
#     current_data = get_current_data()
#     filtered = []
#     for key in stocks:
#         ## 当前开盘价等于涨停
#         if current_data[key].low_limit < current_data[key].last_price:
#             filtered.append(key)
#         else:
#             log.info(
#                 f"由于跌停不能卖出的股票：{key},跌停价:{current_data[key].low_limit},最新价:{current_data[key].last_price}")
#     return filtered
#
#
# def check_sotck(context):
#     low_moeny_stocks = check_low_money_stock(context)
#     print(f"low_moeny_stocks:{low_moeny_stocks}")
#     low_market_cap_stocks = check_low_market_cap_stocks(context)
#     print(f"low_market_cap_stocks:{low_market_cap_stocks}")
#
#     check_sotcks = [stock_code for stock_code in low_market_cap_stocks if stock_code in low_moeny_stocks]
#     print(f"check_sotcks:{check_sotcks}")
#     filtered = filter_st(check_sotcks)
#     print(f"筛选后(is_st=True)的元素: {filtered}")
#     return filtered
#
#
# ## 选出小市值股票
# def check_low_market_cap_stocks(context):
#     # 设定查询条件
#     q = query(
#         valuation.code,
#         valuation.market_cap
#     ).order_by(
#         valuation.market_cap.asc()
#     )
#
#     # 选出低市值的股票，构成buylist
#     df = get_fundamentals(q)
#     buylist = list(df['code'])
#
#     return buylist[:g.stock_num]
#
#
# ## 选出低市值的
# def check_low_money_stock(context):
#     # 获取所有股票列表
#     stocks = list(get_all_securities(['stock']).index)
#
#     # 获取最近20天的收盘价、成交量和成交额数据
#     h = get_price(
#         stocks,
#         end_date=context.current_dt.date(),
#         count=20,
#         frequency='daily',
#         fields=['close', 'money'],
#         panel=False
#     )
#
#     # 1. 按股票代码 'code' 进行分组
#     grouped = h.groupby('code')
#
#     # 2. 为每只股票（每个分组）计算我们需要的统计量
#     # 2.1 最新收盘价 (取组内最后一天的数据，假设数据已按时间排序)
#     latest_close = grouped['close'].last()  # 或者使用 nth(-1)
#
#     # 2.2 最近20日平均成交额 (注意单位：元)
#     sum_money_20d = grouped['money'].sum()
#
#     # 2.3 统计最近20日内成交额超过1000万的天数 (注意单位：元，1000万 = 10,000,000)
#     days_over_10m = grouped['money'].apply(lambda x: (x > 10000000).sum())
#
#     # 3. 将计算出的统计量组合到一个新的DataFrame中
#     condition_df = pd.DataFrame({
#         'close_price': latest_close,
#         'sum_money_20d': sum_money_20d,
#         'days_over_10m': days_over_10m
#     })
#
#     # 4. 应用多重条件筛选
#     # 条件1: 收盘价 > 2 元
#     # 条件2: 20日平均成交额 > 2亿 (2亿 = 200,000,000元)
#     # 条件3: 20日内至少有10天成交额 > 1000万 (1000万 = 10,000,000元)
#     filtered_stocks = condition_df[
#         (condition_df['close_price'] > 2) &
#         (condition_df['sum_money_20d'] > 200000000) &
#         (condition_df['days_over_10m'] >= 10)
#         ]
#
#     # 5. 按收盘价升序排序并取前200只股票
#     lowest_stocks = filtered_stocks.sort_values(by='close_price').head(g.stock_num)
#
#     # 6. 提取最终的股票代码列表
#     selected_stock_list = lowest_stocks.index.tolist()
#
#     return selected_stock_list